package com.example.spider.provider.why10w;

import com.example.spider.provider.why10w.dto.Why10wDetailTask;
import com.example.spider.provider.why10w.dto.Why10wListTask;
import com.example.spider.provider.why10w.persistent.Why10wRepository;
import com.example.spider.starter.SpiderStarter;
import com.example.spider.task.SpiderResultHandler;
import com.example.spider.task.Task;
import com.example.spider.task.limit.FixWindowLimit;
import lombok.extern.slf4j.Slf4j;
import org.shoulder.core.exception.CommonErrorCodeEnum;
import org.shoulder.core.util.AssertUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.Duration;

/**
 * 处理列表查询结果
 *
 * @author lym
 */
@Slf4j
public abstract class AbstractWhy10wListResultHandler implements SpiderResultHandler<Why10wListTask, String>, SpiderStarter {

    static {
        Task.registerType(Why10wListTask.class);
        Task.registerType(Why10wDetailTask.class);
    }

    @Autowired
    protected Why10wRepository repository;
    @Autowired
    protected Why10wFileNameTemplate why10wFileNameTemplate;

    protected final String source;

    protected AbstractWhy10wListResultHandler() {
        String fullName = getClass().getName();
        String pkgName = AbstractWhy10wListResultHandler.class.getName()
                .replace(AbstractWhy10wListResultHandler.class.getSimpleName(), "");
        AssertUtils.isTrue(fullName.contains(pkgName), CommonErrorCodeEnum.CODING);
        String resultName = fullName.replace(pkgName, "");
        int lastDot = resultName.lastIndexOf('.');
        this.source = resultName.substring(0, lastDot);
    }
    protected AbstractWhy10wListResultHandler(String source) {
        this.source = source;
    }

    @Override
    public <R> boolean canHandle(Task<R> task, R result) {
        return task instanceof Why10wListTask && source.equals(((Why10wListTask) task).getSource());
    }

    /**
     * 处理结果
     *
     * @param html 页面信息
     */
    public void handle(Why10wListTask task, String html) {
        log.debug("prepare handing {}: {}", source, task.getUrl());
        try {
            doHandle(task, html);
            log.info("handle finished {}: {}", source, task.getUrl());
        } catch (Exception e) {
            log.error("Fail process {}: {}", source, task.getUrl(), e);
        }
    }

    // 判断本次爬取是否有效，无效跳过

    // 缓存爬取结果

    // 创建爬取详情的任务

    // 创建爬取下一页的任务
    protected abstract void doHandle(Why10wListTask task, String html);

    protected Duration limitPageDuration() {
        return Duration.ofMillis(200);
    }

    protected Duration limitDetailDuration() {
        return Duration.ofMillis(400);
    }

    protected Why10wListTask createPageTask(String firstCategory, String secondCategory, int pageNo) {
        return new Why10wListTask()
                .setSource(source)
                .setFirstCategory(firstCategory)
                .setSecondCategory(secondCategory)
                .setPage(pageNo)
                .setIdempotentFilePath(why10wFileNameTemplate.calculateHtmlFileName(source, "list_" + firstCategory + "_" + secondCategory + "_" + pageNo))
                .setLimitStrategy(new FixWindowLimit(source, limitPageDuration()))
                .setUrl(buildPageTaskUrl(firstCategory, secondCategory, pageNo));
    }

    protected abstract String buildPageTaskUrl(String firstCategory, String secondCategory, int pageNo);

    protected Why10wDetailTask createDetailTask(Why10wListTask task, String id, String title, String url) {
        AssertUtils.notNull(task, CommonErrorCodeEnum.ILLEGAL_PARAM);
        AssertUtils.notNull(id, CommonErrorCodeEnum.ILLEGAL_PARAM);
        AssertUtils.notNull(title, CommonErrorCodeEnum.ILLEGAL_PARAM);
        AssertUtils.notNull(url, CommonErrorCodeEnum.ILLEGAL_PARAM);

        return new Why10wDetailTask()
                .setSource(task.getSource())
                .setId(id)
                .setTitle(title)
                .setFirstCategory(task.getFirstCategory())
                .setSecondCategory(task.getSecondCategory())
                .setIdempotentFilePath(why10wFileNameTemplate.calculateHtmlFileName(source, "detail_" + id))
                .setLimitStrategy(new FixWindowLimit(source, limitDetailDuration()))
                .setUrl(url);
    }
    
}
